package com.macro.mall.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.macro.mall.common.api.CommonResult;
import com.macro.mall.dto.BucketPolicyConfigDto;
import com.macro.mall.dto.MinioUploadDto;
import io.minio.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/** MinIO对象存储管理Controller Created by macro on 2019/12/25. */
@Controller
@Api(tags = "MinioController")
@Tag(name = "MinioController", description = "MinIO对象存储管理")
@RequestMapping("/minio")
public class MinioController {

  private static final Logger LOGGER = LoggerFactory.getLogger(MinioController.class);

  @Value("${minio.endpoint}")
  private String ENDPOINT;

  @Value("${minio.bucketName}")
  private String BUCKET_NAME;

  @Value("${minio.accessKey}")
  private String ACCESS_KEY;

  @Value("${minio.secretKey}")
  private String SECRET_KEY;

  @ApiOperation("文件上传")
  @RequestMapping(value = "/upload", method = RequestMethod.POST)
  @ResponseBody
  public CommonResult upload(@RequestPart("file") MultipartFile file) {
    try {
      // 创建一个MinIO的Java客户端
      MinioClient minioClient =
          MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
      boolean isExist =
          minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());
      if (isExist) {
        LOGGER.info("存储桶已经存在！");
      } else {
        // 创建存储桶并设置只读权限
        minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());
        BucketPolicyConfigDto bucketPolicyConfigDto = createBucketPolicyConfigDto(BUCKET_NAME);
        SetBucketPolicyArgs setBucketPolicyArgs =
            SetBucketPolicyArgs.builder()
                .bucket(BUCKET_NAME)
                .config(JSONUtil.toJsonStr(bucketPolicyConfigDto))
                .build();
        minioClient.setBucketPolicy(setBucketPolicyArgs);
      }
      String filename = file.getOriginalFilename();
      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
      // 设置存储对象名称
      String objectName = sdf.format(new Date()) + "/" + filename;
      // 使用putObject上传一个文件到存储桶中
      PutObjectArgs putObjectArgs =
          PutObjectArgs.builder()
              .bucket(BUCKET_NAME)
              .object(objectName)
              .contentType(file.getContentType())
              .stream(file.getInputStream(), file.getSize(), ObjectWriteArgs.MIN_MULTIPART_SIZE)
              .build();
      minioClient.putObject(putObjectArgs);
      LOGGER.info("文件上传成功!");
      MinioUploadDto minioUploadDto = new MinioUploadDto();
      minioUploadDto.setName(filename);
      minioUploadDto.setUrl(ENDPOINT + "/" + BUCKET_NAME + "/" + objectName);
      return CommonResult.success(minioUploadDto);
    } catch (Exception e) {
      e.printStackTrace();
      LOGGER.info("上传发生错误: {}！", e.getMessage());
    }
    return CommonResult.failed();
  }

  /** 创建存储桶的访问策略，设置为只读权限 */
  private BucketPolicyConfigDto createBucketPolicyConfigDto(String bucketName) {
    BucketPolicyConfigDto.Statement statement =
        BucketPolicyConfigDto.Statement.builder()
            .Effect("Allow")
            .Principal("*")
            .Action("s3:GetObject")
            .Resource("arn:aws:s3:::" + bucketName + "/*.**")
            .build();
    return BucketPolicyConfigDto.builder()
        .Version("2012-10-17")
        .Statement(CollUtil.toList(statement))
        .build();
  }

  @ApiOperation("文件删除")
  @RequestMapping(value = "/delete", method = RequestMethod.POST)
  @ResponseBody
  public CommonResult delete(@RequestParam("objectName") String objectName) {
    try {
      MinioClient minioClient =
          MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
      minioClient.removeObject(
          RemoveObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).build());
      return CommonResult.success(null);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return CommonResult.failed();
  }
}
